<html>
<head>
<title>NotSoSimpleSudoku</title>
<script src="jquery.js"> </script>
<script>
try{
	var cl = console.log,
		ce = console.error,
		json = JSON.stringify;
	function clj( e){
		console.log(JSON.stringify(e));
	}
} catch(e) {
	var cl=ce=json=clj=function(){};
}

// von http://javascript.jstruebig.de/
(function(){
    var s = window.location.search.substring(1).split('&');
    if(!s.length) return;
    var c = {};
    for(var i  = 0; i < s.length; i++)  {
        var parts = s[i].split('=');
        c[unescape(parts[0])] = unescape(parts[1]);
    }
    window.$_GET = function(name){return name ? c[name] : c;}
}())

var Backend = {
	worker:undefined,
	creator:undefined,
	handlers:[],
	count:0,
	log:1,
	init: function( filename){
		this.worker = new Worker(filename);
		this.worker.onmessage = this.catchMessage;
	},
	request: function( cmd, args, callback, context){
        if( this.log){
            cl("to Backend:",{
                cmd:cmd,
                args:args,
                refid:this.count
            });
        }
		this.worker.postMessage({
			cmd:cmd,
			args:args,
			refid:this.count
		});
		
		this.handlers.push({
			refid:this.count,
			callback:callback,
			context:context
		});
		this.count++;
	},
	
	catchMessage: function(e){
        if( Backend.log){
            cl("from Backend:", e.data);        
        } else if( e.data.cmd === "cl"){
			cl( e.data.args.value);
			return;
		} else if( e.data.cmd === "ce"){
			ce( e.data.args.value);
			return;
		} else if( e.data.cmd==="void"){
			return;
		}
		var temp= Backend.handlers.filter( function( handle){
			return handle.refid === e.data.refid;
		});
		if( temp.length === 0){
			ce( "Message from working incoming but no suitable handler found.");
			cl( e.data);
			return;
		}
		if( temp.length > 1)
			throw "Too many handlers.";
		temp[0].callback.call( temp[0].context, e.data);
	}

};

var sdkGFX = {

    cache: {},

	init: function(){
		Backend.request("get_multiple", {values:["candidIDs","cellIDs","cellsToHouses"]}, this.createField);
		Backend.request("get",{value:"style"},this.getStyle);
		Backend.request("get",{value:"predefined"}, this.getPredefined);
	},
	
	createField : function(e){
		var cellsToHouses = e.args.cellsToHouses,
			insert = $("<div />"),
			cellDummy = $('<div />', {"class":"cell"}),
			candidDummy = $('<span />', {"class":"candid"});
		
		for( var i=0, candidID; candidID=e.args.candidIDs[i],i<e.args.candidIDs.length;i++){
			candidDummy.clone().attr('candidID',candidID).attr('id','_'+candidID).html(candidID).appendTo(cellDummy);
		};
		
		for( var i=0,cellID; cellID=e.args.cellIDs[i],i<e.args.cellIDs.length;i++){
			cellDummy.clone()
            .attr({
                id: cellID, 
                houses: cellsToHouses[cellID].join(' ')
            })
            .children()
                .attr("id",function(i, old){
                        return cellID+old;
                    })
            .end()
            .appendTo( insert);
		};
		insert.appendTo("#sdkWrapper");
		
		var toolDummy = $('<span></span>').addClass('button'),
			insert = $("<div></div>");
			
		for( var i=0, candidID; candidID=e.args.candidIDs[i],i<e.args.candidIDs.length;i++){
			toolDummy.clone().attr('candidid',candidID).html(candidID).appendTo(insert);
		};
		
		insert.children().appendTo("#toolWrapper");
		
	},
	
	getStyle: function( e){		
		function helper( selector, styles){
			var ret = selector+ " {\n\t";
			for( var style in styles){
				ret += style + " : "+styles[style]+";\n\t";
			}
			ret += "}\n";
			return ret;
		}
		
		var htmlStyle= $('<style />');
		for( var style in e.args.value){
			htmlStyle.append( helper( style, e.args.value[style]));
		}
		$("#workerstyle").append(htmlStyle.text());
	},
	
	getPredefined: function( e){
        var rnd = Math.floor(Math.random()*e.args.value.length);
		$("#inputfield").val(e.args.value[rnd]).submit();
	},
	
	click: function(e){
        var id=this.id.split('_');
		Backend.request("change",{value:"swap",cellID:id[0],candidID:id[1]}, sdkGFX.redrawField);
	},
	
	dblclick: function(e){
		var id=this.id.split('_');
		Backend.request("change",{value:"only",cellID:id[0],candidID:id[1]}, sdkGFX.redrawField);	
	},
	
	redrawField: function(e){
		for( var cell,i=0; cell=e.args.value[i], i<e.args.value.length; i++){
			var candids = $("#"+cell.id)
				.children()
				.removeAttr('only')
				.attr('enabled',function( index, attr){
                    return cell.candids.indexOf( $(this).attr('candidid')) >=0 ? "enabled": "";
				})
				.filter('[enabled="enabled"]');
				
			if( candids.size() == 1)
				candids.attr('only','only');
		};
	},
	
	load: function( sz){
		Backend.request("init",{field: sz},this.redrawField);
	},
	
	highlight: function(candidID){
		$("span.candid","#sdkWrapper").attr('highlight',function(index, attr){
            return $(this).attr('candidid') === candidID ? "highlight" : "";
		});
	}
};



$(function() {
	Backend.init($_GET("variantfile")||"classic.js");
	sdkGFX.init();
	
	$('#nakedsingle').click(function(e){
		Backend.request("calc",{value:"Naked Single"}, sdkGFX.redrawField);
	});
	$('#hiddensingle').click(function(e){
		Backend.request("calc",{value:"Hidden Single"}, sdkGFX.redrawField);
	});
	$('#inputform').submit(function(e){
		e.preventDefault();
		sdkGFX.load($('#inputfield').val());
	});
	$('#incFontsize').click(function(e){
		$('#sdkWrapper').css('font-size', function(index, old){
            return /[\d.]+/.exec(old)[0]*1.25+"px";
        });
	});
	$('#decFontsize').click(function(e){
		$('#sdkWrapper').css('font-size', function(index, old){
            return /[\d.]+/.exec(old)[0]*0.8+"px";
        });
	});
	$('.candid','#sdkWrapper').live('click',sdkGFX.click).live('dblclick',sdkGFX.dblclick);
	$('.button','#toolWrapper').live('click',function(e){
		sdkGFX.highlight($(this).attr('candidid'));
	});
});

</script>
<style id="default" lang="CSS">
body {
	background-color: #FAFAFA;
	height: 100%;
	width: 100%;
	padding: 0px;
	margin: 0px;
}

a[href=""], a:not([href]) {
	text-decoration: line-through;
}

#topbar {
	background-color:#E5ECF9;
	border-bottom:thin solid #3366CC;
	width: 100%;
	top: 0%;
	left: 0%;
}

.irgendwas {
	
	
	border-bottom: #C9D7F1 thin solid;
}

.centerchild{
	width: 100%;
	text-align: center;
}

#toolWrapper {
	height: 50px;
}

.button {
	width: 30px;
	color: black;
	font-family: monospace;
	font-size: 18px;
	font-weight: bold;
	cursor: pointer;
}

.button + .button::before {
	content:"|";
	color: #ABABAB;
	
}

#sdkWrapper {
	display: inline-block;
	position: relative;
	width: 27em;
	height: 27em;
	font-size: 4.4mm;
	background: white;
}

.cell {
	border: gray thin dotted;
	width: 11.22%;
	height: 11.22%;
	position: absolute;
	background: white;
	overflow: hidden;
}

.candid {
	font-family: monospace;
	font-size: 100%;
	position: absolute;
	left:0%;
	top:0%;
	cursor:pointer;
}



.candid:not([enabled="enabled"]) {
	color: #DDDDDD;
}

#inputfield {
	width: 50%;
	position: fixed;
	bottom: 0px;
	color: gray;
	left: 25%;
}

</style>
<style id="workerstyle">

</style>
<style id="randstyle">
.candid[only] {
	font-family: 'Comic Sans MS';
	font-size: 300%;
	left: 20%;
	top: -20%;
	position: absolute;
	z-index:1;
}

.candid[highlight="highlight"][enabled="enabled"]:not([only]) {
	background: limegreen;
}
</style>
</head>
<body>
<div id="topbar"><a>New</a> <a>About</a> <a href="javascript:void(0);" id="incFontsize">+A</a> <a href="javascript:void(0);" id="decFontsize">-a</a></div>
<br /><br />
<div class="centerchild">
	<div id="toolWrapper"></div>

	<div id="sdkWrapper"></div>

	<br/><br/>
	<a href="javascript:void(0);" id="nakedsingle">Naked Single</a>
	<a href="javascript:void(0);" id="hiddensingle">Hidden Single</a>
</div>
<form id="inputform">
	<input id="inputfield" type="text" value="" />
</form>
</body>
</html>